﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

#include "CmdPickWithInteractivePicker.h"
#include "IPick.h"
#include "Vector3d.h"
#include "IDocument.h"
#include "ActionBase.h"
#include "ISelection.h"
#include "IPickFilter.h"
#include "IPickTarget.h"
#include "IPickResult.h"
#include "IUiDocument.h"
#include "IHighlights.h"
#include "IPreHighlights.h"
#include "IPickEventArgs.h"
#include "IPickCandidates.h"
#include "GcmpCommandState.h"
#include "IPickEventHandler.h"
#include "InteractivePicker.h"
#include "UiDocumentViewUtils.h"
#include "IGraphicsNodeReference.h"
#include "PickNodeReferenceOption.h"
#include "IPickNodeReferenceAction.h"

#include <iostream>
#include <Windows.h>
#include "PickFilterDlg.h"
#include "CommandRegister.h"
#include "SampleUIUtils.h"
#include "PickSnapCommandIds.h"
#include "CmdPickModuleEntry.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

using namespace gcmp;
using namespace Sample;

#pragma region 拾取过滤器和拾取事务
namespace Sample
{
    // 拾取过滤器
    class PickWithInteractivePickerActionFilter : public IPickFilter
    {
    public:
        PickWithInteractivePickerActionFilter(PickFilterDlg* pPickFilterDlg)
        {
            DBG_WARN_AND_RETURN_VOID_UNLESS(pPickFilterDlg, L"pPickFilterDlg为空",L"GDMP",L"2023-12-30");
            m_pickFilterDlg = pPickFilterDlg;
        }

        virtual bool AllowElement(const gcmp::ElementId& elementId) const override
        {
            // 根据Ribbon菜单的AllowElement选项
            return m_pickFilterDlg->AllowElement();
        }

        virtual bool AllowGraphicsNode(const gcmp::IGraphicsNodeReference& graphicsNodeReference) const override
        {
            // 根据Ribbon菜单的AllowGraphicsNode选项
            return m_pickFilterDlg->AllowGraphicsNode();
        }

        virtual bool SetPickTargetOption(gcmp::IPickTarget* pPickTarget) override
        {
            // 根据拾取过滤栏设置IPickTarget选项
            m_pickFilterDlg->SetPickTarget(pPickTarget);
            return true;
        }
    private:
        PickFilterDlg* m_pickFilterDlg;
    };

    class PickWithInteractiveEventHandler : public gcmp::IPickEventHandler
    {

    public:
        virtual void On(gcmp::IPickEventArgs* pArgs) override
        {
            // 在底部状态栏按照拾取候选集顺序显示拾取候选项
            const IPickResult& pPickResult = pArgs->GetPickCandidates();
            std::wstring tooltip = L"IPickEventArgs.IPickResult: ";
            for (const OwnerPtr<IGraphicsNodeReference>& itor : pPickResult.GetAllGraphicsNodeReferences())
            {
                DBG_WARN_AND_RETURN_VOID_UNLESS(itor, L"itor为空",L"GDMP",L"2023-12-30");
                tooltip += itor->GetDescriptionString() + L"; ";
                // TODO:GBMP-45577 信息太长会导致主窗口变形
                break;
            }
            SampleUIUtils::SetStatusBarPromptMessage(tooltip);
        }
    };
}
#pragma endregion 拾取过滤器和拾取事务

#pragma region CmdPickWithInteractivePicker
REGISTER_COMMAND(CmdPickWithInteractivePicker)

CmdPickWithInteractivePicker::CmdPickWithInteractivePicker() : CommandBase(ID_CMD_PICK_WITH_INTERACTIVE_PICKER)
{
}

CmdPickWithInteractivePicker::~CmdPickWithInteractivePicker(){}

bool CmdPickWithInteractivePicker::IsEnabled() const
{
    return GcmpCommandState::IsInDocumentEnvironment() && (CmdPickModuleEntry::GetPickMethod() == PickMethod::InteractivePicker);
}

bool CmdPickWithInteractivePicker::IsVisible() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

gcmp::OwnerPtr<gcmp::IAction> CmdPickWithInteractivePicker::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    PickFilterDlg* pPickFilterDlg = PickFilterDlg::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPickFilterDlg, L"pPickFilterDlg为空",L"GDMP",L"2023-12-30");
    pPickFilterDlg->show();

    while (true)
    {
    // 根据Ribbon菜单设置是否多选
    bool isMultiple = CmdPickModuleEntry::DoSelectMultiple();

    // 拾取结果回参
    bool isPickPointSelect = true;
    Vector3d point;
    GraphicsNodeReferenceOwnerPtrVector nodeReferences;

    // 用界面拾取过滤栏初始化IPickEventHandler和IPickTarget
    OwnerPtr<PickWithInteractiveEventHandler> opPickEventHandler = NEW_AS_OWNER_PTR(PickWithInteractiveEventHandler);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opPickEventHandler, L"opPickEventHandler为空",L"GDMP",L"2023-12-30");
    OwnerPtr<PickWithInteractivePickerActionFilter> opPickerFilter = NEW_AS_OWNER_PTR(PickWithInteractivePickerActionFilter, pPickFilterDlg);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opPickerFilter, L"opPickerFilter为空",L"GDMP",L"2023-12-30");
    OwnerPtr<IPickTarget> opPickTarget = IPickTarget::Create();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opPickTarget, L"opPickTarget为空",L"GDMP",L"2023-12-30");
    pPickFilterDlg->SetPickTarget(opPickTarget.get());
    opPickerFilter->SetPickTargetOption(opPickTarget.get());

    // 开始拾取
        InteractivePicker::PickerResult result = InteractivePicker::Select(isMultiple, isPickPointSelect, 
            TransferOwnership(opPickerFilter), L"选择", L"选择", point, nodeReferences, false, TransferOwnership(opPickEventHandler));

        if (result.FinishStatus != InteractivePicker::PickerFinishStatus::Successful)
        {
            return nullptr;
        }

    // 不是所有的拾取操作都需要选择。根据Ribbon菜单的选择拾取图元，决定是否将拾取候选集放入选择集
    if (CmdPickModuleEntry::DoSelectPicked())
    {
        IPreHighlights* pPreHighlights = IPreHighlights::Get();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPreHighlights, L"pPreHighlights为空",L"GDMP",L"2023-12-30");
        pPreHighlights->Clear();

        IDocument* pDocument = UiDocumentViewUtils::GetCurrentDocument();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDocument, L"pDocument为空",L"GDMP",L"2023-12-30");
        ISelection* pSelection = ISelection::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pSelection, L"pSelection为空",L"GDMP",L"2023-12-30");
        pSelection->Clear(pDocument);

        IHighlights* pHighlights = IHighlights::Get();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pHighlights, L"pHighlights为空",L"GDMP",L"2023-12-30");
        pHighlights->Clear();

        IPickCandidates* pPickCandidates = IPickCandidates::Get();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPickCandidates, L"pPickCandidates为空",L"GDMP",L"2023-12-30");

        if (const OwnerPtr<IPick>& opPick = pPickCandidates->GetCurrentPick())
        {
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opPick, L"opPick为空",L"GDMP",L"2023-12-30");
            if (const IGraphicsNodeReference* pGraphicsNodeReference = opPick->GetFront())
            {
                DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGraphicsNodeReference, L"pGraphicsNodeReference为空",L"GDMP",L"2023-12-30");
                pSelection->AddGraphicsNodeReference(pDocument, *pGraphicsNodeReference);
                pHighlights->AddGraphicsNodeReference(*pGraphicsNodeReference);
            }
        }

        // 记得刷新视图，否则高亮预高亮显示可能不会立刻刷新
        IUiDocument* pUiDocument = UiDocumentViewUtils::GetCurrentUiDocument();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDocument, L"pUiDocument为空",L"GDMP",L"2023-12-30");
        pUiDocument->UpdateView();
    }
    }
    return nullptr;
}

// 是否在启动Command前清空之前的选择集
bool CmdPickWithInteractivePicker::ShouldClearSelectionBeforeExecution() const
{
    bool clearSelectionBeforeExecution = CmdPickModuleEntry::DoClearSelectionBeforeCmd();
    return clearSelectionBeforeExecution;
}
#pragma endregion CmdPickWithInteractivePicker

